package com.log.search.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.log.search.dto.FileDto;
import com.log.search.dto.LogInfoDto;
import com.log.search.dto.LogSearchDto;
import com.log.search.entity.AppInstance;
import com.log.search.entity.Shell;
import com.log.search.mapper.AppInstanceMapper;
import com.log.search.service.LogService;
import com.log.search.util.CommonUtils;
import com.log.search.util.ShellUtils;
import com.log.search.util.ThreadPoolUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

@Slf4j
@Service
public class LogServiceImpl implements LogService {
    @Autowired
    private AppInstanceMapper instanceMapper;
    @Autowired
    HttpServletRequest request;

    private String LOCAL_ADDRESS = "127.0.0.1";

    @Override
    public List<LogInfoDto>  searchLog(LogSearchDto searchDto) {
        List<AppInstance> appInstances = instanceMapper.selectList(
            new QueryWrapper<AppInstance>()
                .eq("app_id", searchDto.getAppId())
        );
        List<LogInfoDto> logInfoList = new ArrayList<>();
        List<Future<LogInfoDto>> futures = new ArrayList<>();
        String ipAddress = CommonUtils.getIpAddress(request);
        for (AppInstance appInstance : appInstances) {

            Future<LogInfoDto> future = ThreadPoolUtil.submit(() -> getLogInfo(searchDto, appInstance,ipAddress));
            futures.add(future);
        }
        for (Future<LogInfoDto> future : futures) {
            try {
                LogInfoDto logInfoDto = future.get();
                logInfoList.add(logInfoDto);
            }catch (Exception e){
                log.error("日志查询执行异常",e);

            }

        }

        return logInfoList;

    }

    @Override
    public List<LogInfoDto> allSearch(LogSearchDto searchDto) {
        List<AppInstance> appInstances = instanceMapper.selectList(
            new QueryWrapper<AppInstance>()
                .eq("app_id", searchDto.getAppId())
        );
        List<LogInfoDto> logInfoList = new ArrayList<>();
        List<Future<LogInfoDto>> futures = new ArrayList<>();
        String ipAddress = CommonUtils.getIpAddress(request);

        for (AppInstance appInstance : appInstances) {

            Future<LogInfoDto> future = ThreadPoolUtil.submit(() -> getLogInfo(searchDto, appInstance,ipAddress));
            futures.add(future);
        }
        for (Future<LogInfoDto> future : futures) {
            try {
                LogInfoDto logInfoDto = future.get();
                logInfoList.add(logInfoDto);
            }catch (Exception e){
                log.error("全文日志查询执行异常",e);

            }

        }
        return logInfoList;
    }

    private LogInfoDto getLogInfo(LogSearchDto searchDto,  AppInstance appInstance,String ipAddress) {


        StringBuilder sb = new StringBuilder("cat ");
        sb.append(appInstance.getLogPath());
        sb.append(searchDto.getFileName());
        //如果endNum大于0，则代表查询前N行
        if(searchDto.getEndNum() != null && searchDto.getEndNum() !=0){
            sb.append(" | head  -n ");
            sb.append(searchDto.getEndNum());
        }
        sb.append(" | tail -n ");
        sb.append(searchDto.getTailNum());
        if(!StrUtil.isBlank(searchDto.getKeyword())) {
            sb.append(" | grep ");
            sb.append("'");
            sb.append(searchDto.getKeyword());
            sb.append("'");
            sb.append(" -");
            sb.append(searchDto.getUpLine());
        }
        List<String> outList = new ArrayList<>();
        //判断是不是本地
        if(appInstance.getShellHost().equalsIgnoreCase(LOCAL_ADDRESS)){
            log.info("用户ip:{},本机开始查询文件",ipAddress);
            outList = ShellUtils.getLocalList(sb.toString());
            log.info("用户ip:{},本机查询文件结束",ipAddress);

        }else {
            Shell shell = new Shell();
            shell.setIp(appInstance.getShellHost());
            shell.setPort(appInstance.getShellPort());
            shell.setUsername(appInstance.getShellUser());
            shell.setPassword(appInstance.getShellPass());
            log.info("用户ip:{},服务器ip:{} 开始查询日志",ipAddress,appInstance.getShellHost());
            outList = ShellUtils.exec(shell,sb.toString());
            log.info("用户ip:{},服务器ip:{} 查询日志结束",ipAddress,appInstance.getShellHost());
        }

        LogInfoDto logInfoDto = new LogInfoDto();
        //增加获取实例别名
        logInfoDto.setHostName(appInstance.getHostName());
        logInfoDto.setShellHost(appInstance.getShellHost());
        logInfoDto.setKeyword(searchDto.getKeyword());
        if(!StrUtil.isBlank(searchDto.getKeyword()) && !CollectionUtils.isEmpty(outList)){
            String highLight = "<a style='background: #e6ff5b'>" + searchDto.getKeyword() + "</a>";
            outList.replaceAll(e->e.replaceAll(searchDto.getKeyword(),highLight));
        }
        logInfoDto.setLogs(outList);
        return logInfoDto;
    }


    @Override
    public List<FileDto> searchFileName(long appId,String folder) {
        List<AppInstance> appInstances = instanceMapper.selectList(
            new QueryWrapper<AppInstance>()
                .eq("app_id", appId)
        );
        List<Future<List<String>>> futures = new ArrayList<>();
        String ipAddress = CommonUtils.getIpAddress(request);

        for (AppInstance appInstance : appInstances) {

            Future<List<String>> future = ThreadPoolUtil.submit(() -> getFileName(appInstance,folder,ipAddress));
            futures.add(future);
        }
        List<FileDto> fileDtos = new ArrayList<>();
        for (Future<List<String>> future : futures) {
            try {
                List<String> fileNames = future.get();
                for (String fileName : fileNames) {
                    this.parseFileNames(fileDtos, fileName);
                }
            }catch (Exception e){
                log.error("文件查询执行异常",e);

            }
        }
        return fileDtos;
    }
    private List<String> getFileName(AppInstance appInstance,String folder,String ipAddress) {
        log.info("用户ip:{},服务器ip:{} 开始查询文件",ipAddress,appInstance.getShellHost());
        String cmd = "ls -l  " +appInstance.getLogPath()+folder + " | awk '{print $1, $9}'";
        //判断是不是本地
        if(appInstance.getShellHost().equalsIgnoreCase(LOCAL_ADDRESS)){
            List<String> localList = ShellUtils.getLocalList(cmd);
            log.info("用户ip:{},本机查询文件结束",ipAddress);
            return localList;
        }
        Shell shell = new Shell();
        shell.setIp(appInstance.getShellHost());
        shell.setPort(appInstance.getShellPort());
        shell.setUsername(appInstance.getShellUser());
        shell.setPassword(appInstance.getShellPass());
        List<String> outList = ShellUtils.exec(shell,cmd);
        log.info("用户ip:{},服务器ip:{} 查询文件结束",ipAddress,appInstance.getShellHost());

        return outList;
    }
    private void parseFileNames(List<FileDto> fileDtos, String fileName) {
        if(StrUtil.isBlank(fileName)) {
            return;
        }
        //多个空格替换成一个空格如:a 5   8a    47=>a 5 8a 47
        fileName = CommonUtils.replaceBlank(fileName," ");
        String[] infos = fileName.split(" ");
        //小于2则是total，不是文件名称，不需要返回
        if(infos.length <2){
            return;
        }
        FileDto fileDto = new FileDto();
        //最后一个字段是文件名
        fileDto.setName(infos[infos.length-1]);
        ////0文件夹，1文件
        if(infos[0].startsWith("-")){
            fileDto.setType(1);
        }else {
            fileDto.setType(0);
        }
        this.addFile(fileDtos,fileDto);
    }

    private void addFile(List<FileDto> fileDtos, FileDto fileDto){
        for (FileDto dto : fileDtos) {
            if(dto.getName().equals(fileDto.getName()) && dto.getType() == fileDto.getType()){
                return;
            }
        }
        fileDtos.add(fileDto);
    }



}
